package de.tuhh.simsearch.webinterface.rest;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import de.tuhh.simsearch.constants.Constants;
import de.tuhh.simsearch.constants.Constants.FilterType;
import de.tuhh.simsearch.constants.Constants.SearchTypes;
import de.tuhh.simsearch.controller.RequestHandlerLocal;
import de.tuhh.simsearch.dto.CategoryDTO;
import de.tuhh.simsearch.dto.FileDTO;
import de.tuhh.simsearch.dto.GroupDTO;
import de.tuhh.simsearch.dto.PasswordDTO;
import de.tuhh.simsearch.dto.PreferenceDTO;
import de.tuhh.simsearch.dto.UserDTO;
import de.tuhh.simsearch.webinterface.helper.ResponseObject;

/**
 * RESTAccess handles most REST requests from the client and delivers the requests as method calls to the
 * {@link RequestHandlerLocal}. The path to this REST servlet is 'path/access'. The parameters for the functions are either
 * submitted in the URL or as JSON messages.
 * 
 * @author SimSearch 1
 * 
 * @see RequestHandlerLocal
 */
@Path("access")
@Stateless
public class RESTAccess {

  @EJB private RequestHandlerLocal reqHandler;

  @Inject private HttpServletRequest httpReq;

  /*
   * ################ Getting Rescources ##############
   */

  /**
   * Handles a GET request on path 'users/search/{queryString}, where {queryString} is the parameter query. The database
   * is searched for users whos names contain the query string.
   * 
   * @param query
   *          the string {queryString}
   * @return the list of {@link UserDTO}s.
   */
  @GET
  @Path("users/search/{queryString}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<UserDTO> searchUsers(@PathParam(value = "queryString") String query) {

    List<UserDTO> l = reqHandler.searchUsers(query);

    return l;

  }

  /**
   * Handles a GET request on path 'users/{userName}'. Gets a user dto for a user name.
   * 
   * @param name
   *          the user name given in {userName}
   * @return the resulting {@link UserDTO}
   */
  @GET
  @Path("users/{userName}")
  @Produces(MediaType.APPLICATION_JSON)
  public UserDTO getUser(@PathParam(value = "userName") String name) {

    UserDTO user = reqHandler.getUser(name);

    return user;

  }

  /**
   * Handles a GET request on path 'users/groups'. Gets the groups of the current principal
   * 
   * @return the list of {@link GroupDTO}s for all groups the current principal is a member of
   */
  @GET
  @Path("users/groups")
  @Produces(MediaType.APPLICATION_JSON)
  public List<GroupDTO> getGroupsOfUser() {

    List<GroupDTO> grpDtos = reqHandler.getJoinedGroups(httpReq.getUserPrincipal().getName());

    return grpDtos;

  }

  /**
   * Handles a GET request on path 'groups/search/{queryString}'. Searches within group names for a string.
   * 
   * @param query
   *          the string to search for given in {queryString}
   * @return the list of resulting {@link GroupDTO}s
   */
  @GET
  @Path("groups/search/{queryString}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<GroupDTO> searchGroups(@PathParam(value = "queryString") String query) {

    List<GroupDTO> l = reqHandler.searchGroups(query);

    return l;

  }

  /**
   * Handles a GET request on 'groups/{groupName}'. Gets the group dto for the group with the given name.
   * 
   * @param name
   *          the group name given in {groupName}
   * @return the resulting {@link GroupDTO}
   */
  @GET
  @Path("groups/{groupName}")
  @Produces(MediaType.APPLICATION_JSON)
  public GroupDTO getGroup(@PathParam(value = "groupName") String name) {

    GroupDTO g = reqHandler.getGroup(name);

    return g;

  }

  /**
   * Handles a GET request on 'groups/{groupName}/membership'. Checks if a user is in a group.
   * 
   * @param gName
   *          the group name given in {groupName}
   * @return a {@link ResponseObject}, which contains success or if user is in group or failure otherwise
   */
  @GET
  @Path("groups/{groupName}/membership")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject isUserInGroup(@PathParam(value = "groupName") String gName) {

    boolean isParticipant = false;
    ResponseObject resp = new ResponseObject();

    isParticipant = reqHandler.isUserInGroup(httpReq.getUserPrincipal().getName(), gName);

    if (isParticipant) {
      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("");
    } else {
      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("");
    }

    return resp;
  }

  /**
   * Handles a GET request on path 'groups/{groupName}/isadmin'. Checks if the current principal user is the
   * administrator of the given group.
   * 
   * @param gName
   *          the name of the group given in {groupName}
   * @return a {@link ResponseObject} containing success if user if administrator of the group, failure otherwise
   */
  @GET
  @Path("groups/{groupName}/isadmin")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject isUserGroupAdmin(@PathParam(value = "groupName") String gName) {

    boolean isAdmin = false;
    ResponseObject resp = new ResponseObject();

    isAdmin = reqHandler.isUserGroupAdmin(httpReq.getUserPrincipal().getName(), gName);

    if (isAdmin) {
      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("");
    } else {
      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("");
    }

    return resp;
  }

  /**
   * Handles a GET request on path 'users/iscontentadmin'. Checks if the current principal is a content administrator.
   * 
   * @return a {@link ResponseObject} containing success if the user is administrator, otherwise failure
   */
  @GET
  @Path("users/iscontentadmin")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject isContentAdmin() {

    boolean isAdmin = false;
    ResponseObject resp = new ResponseObject();

    isAdmin = reqHandler.isUserContentAdmin(httpReq.getUserPrincipal().getName());

    if (isAdmin) {
      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("");
    } else {
      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("");
    }

    return resp;
  }

  /**
   * Handles a GET request for path 'preferences/{preferencename}/contentType/{conttype}'. Gets the preference dto for a
   * preference name / content type combination
   * 
   * @param name
   *          the name of the preference given in {preferencename}
   * @param contType
   *          the content type of the preference given in {conttype}
   * @return the {@link PreferenceDTO}
   */
  @GET
  @Path("preferences/{preferencename}/contentType/{conttype}")
  @Produces(MediaType.APPLICATION_JSON)
  public PreferenceDTO getPreference(@PathParam(value = "preferencename") String name,
      @PathParam(value = "conttype") String contType) {

    PreferenceDTO p = reqHandler.getPreference(name, contType);

    return p;
  }

  /**
   * Handles a GET request on 'preferences/user'. Gets the preferences of the current principal.
   * 
   * @return the list of {@link PreferenceDTO}s of the principal
   */
  @GET
  @Path("preferences/user")
  @Produces(MediaType.APPLICATION_JSON)
  public List<PreferenceDTO> getUsersPreferences() {

    List<PreferenceDTO> pdtos = reqHandler.getPreferences(httpReq.getUserPrincipal().getName());

    return pdtos;
  }

  /**
   * Handles a GET request on path 'preferences/search/{queryString}'. Searches for a preference with a name containing
   * a search string.
   * 
   * @param query
   *          the search query given in {queryString}
   * @return the list of {@link PreferenceDTO}s.
   */
  @GET
  @Path("preferences/search/{queryString}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<PreferenceDTO> searchPreference(@PathParam(value = "queryString") String query) {

    List<PreferenceDTO> list = reqHandler.searchPreferences(query);

    return list;
  }

  /**
   * Handles a GET request on path 'categories/search/{queryString}'. Searches for a category with a name containing a
   * certain string
   * 
   * @param query
   *          the query string given in {queryString}
   * @return the list of resulting {@link CategoryDTO}s.
   */
  @GET
  @Path("categories/search/{queryString}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<CategoryDTO> searchCategory(@PathParam(value = "queryString") String query) {

    List<CategoryDTO> list = reqHandler.searchCategories(query);

    return list;
  }

  /**
   * Handles GET-Request for a content search on path
   * 'content/search/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}'.
   * 
   * @param query
   *          The string to search for
   * @param filtered
   *          contains 'true' if search should be filtered for trustful users, 'false' otherwise , given in {filtered}
   * @param filterPrefs
   *          contains 'true' if search should be filtered for the preferences of the principal, 'false' otherwise,
   *          value is given in {filterPrefs}
   * @return the list of {@link FileDTO}s found by the search
   */
  @GET
  @Path("content/search/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<FileDTO> searchContent(@PathParam(value = "queryString") String query,
      @PathParam(value = "filtered") String filtered, @PathParam(value = "filterPrefs") String filterPrefs) {

    FilterType filter = getFilterType(filtered, filterPrefs);
    String principal = null;
    if (httpReq.getUserPrincipal() != null) {
      principal = httpReq.getUserPrincipal().getName();
    }

    List<FileDTO> list = reqHandler.searchContent(query, filter, principal, null);

    return list;

  }

  /**
   * Handles GET request on path 'content/searchbyname/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}'.
   * Searches within the files by filename.
   * 
   * @param query
   *          The string to search for
   * @param filtered
   *          contains 'true' if search should be filtered for trustful users, 'false' otherwise , given in {filtered}
   * @param filterPrefs
   *          contains 'true' if search should be filtered for the preferences of the principal, 'false' otherwise,
   *          value is given in {filterPrefs}
   * @return the list of {@link FileDTO}s found by the search
   */
  @GET
  @Path("content/searchbyname/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<FileDTO> searchContentByName(@PathParam(value = "queryString") String query,
      @PathParam(value = "filtered") String filtered, @PathParam(value = "filterPrefs") String filterPrefs) {

    Set<SearchTypes> searchType = new HashSet<SearchTypes>();
    searchType.add(SearchTypes.NAMES);

    String principal = null;
    if (httpReq.getUserPrincipal() != null) {
      principal = httpReq.getUserPrincipal().getName();
    }

    FilterType filter = getFilterType(filtered, filterPrefs);

    List<FileDTO> list = reqHandler.searchContent(query, filter, principal, searchType);
    // reqHandler.searchContentInName(query, filter, httpReq.getUserPrincipal().getName());

    return list;

  }

  /**
   * Handles GET request on path 'content/searchbycategory/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}'.
   * Searches within the files by category.
   * 
   * @param query
   *          The string to search for
   * @param filtered
   *          contains 'true' if search should be filtered for trustful users, 'false' otherwise , given in {filtered}
   * @param filterPrefs
   *          contains 'true' if search should be filtered for the preferences of the principal, 'false' otherwise,
   *          value is given in {filterPrefs}
   * @return the list of {@link FileDTO}s found by the search
   */
  @GET
  @Path("content/searchbycategory/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<FileDTO> searchContentByCategory(@PathParam(value = "queryString") String query,
      @PathParam(value = "filtered") String filtered, @PathParam(value = "filterPrefs") String filterPrefs) {

    Set<SearchTypes> searchType = new HashSet<SearchTypes>();
    searchType.add(SearchTypes.CATEGORIES);

    String principal = null;
    if (httpReq.getUserPrincipal() != null) {
      principal = httpReq.getUserPrincipal().getName();
    }

    FilterType filter = getFilterType(filtered, filterPrefs);

    List<FileDTO> list = reqHandler.searchContent(query, filter, principal, searchType);

    return list;

  }

  /**
   * Handles GET request on path
   * 'content/searchbydescription/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}'. Searches for files that
   * contain the search string in their description.
   * 
   * @param query
   *          The string to search for
   * @param filtered
   *          contains 'true' if search should be filtered for trustful users, 'false' otherwise , given in {filtered}
   * @param filterPrefs
   *          contains 'true' if search should be filtered for the preferences of the principal, 'false' otherwise,
   *          value is given in {filterPrefs}
   * @return the list of {@link FileDTO}s found by the search
   */
  @GET
  @Path("content/searchbydescription/{queryString}/filtered/{filtered}/filterPrefs/{filterPrefs}")
  @Produces(MediaType.APPLICATION_JSON)
  public List<FileDTO> searchContentByDescription(@PathParam(value = "queryString") String query,
      @PathParam(value = "filtered") String filtered, @PathParam(value = "filterPrefs") String filterPrefs) {

    Set<SearchTypes> searchType = new HashSet<SearchTypes>();
    searchType.add(SearchTypes.DESCRIPTION);

    String principal = null;
    if (httpReq.getUserPrincipal() != null) {
      principal = httpReq.getUserPrincipal().getName();
    }

    FilterType filter = getFilterType(filtered, filterPrefs);

    List<FileDTO> list = reqHandler.searchContent(query, filter, principal, searchType);

    return list;

  }

  /**
   * Handles a GET request on path 'content/{fileID}'. Gets a file given a file id.
   * 
   * @param fileID
   *          the file id as a string given by {fileID}
   * @return the {@link Response}, containing the file to download
   */
  @GET
  @Path("content/{fileID}")
  @Produces(MediaType.APPLICATION_OCTET_STREAM)
  public Response getContent(@PathParam(value = "fileID") String fileID) {

    InputStream in = null;
    Response resp = null;
    BigInteger id = null;
    FileDTO fdto = null;

    try {

      id = BigInteger.valueOf(Long.parseLong(fileID));
      in = reqHandler.downloadFile(id);
      fdto = reqHandler.getFileInfo(id);

    } catch (NumberFormatException nfe) {

      nfe.printStackTrace();
    }

    if (id != null && in != null && fdto != null) {

      resp = Response.ok(in, MediaType.APPLICATION_OCTET_STREAM).build();
      resp.getHeaders().putSingle("Content-Disposition",
          "attachment; filename=" + '"' + fdto.getDisplayedFilename() + '"');

      String contType = "";
      if (httpReq.getHeader("User-Agent").contains("Chrome")) {

        contType = "application/octet-stream";
      } else {

        switch (fdto.getContentType()) {

          case Constants.MusicContentDesc:
            contType = "application/music";
            break;
          case Constants.PictureContentDesc:
            contType = "application/image";
            break;
          case Constants.TextContentDesc:
            contType = "application/text";
            break;
        }
      }

      resp.getHeaders().putSingle("Content-Type", contType);
    }

    return resp;

  }

  /*
   * ################ Creating Rescources ##############
   */

  /**
   * Handles a POST request on path
   * 'content/filename/{fname}/contenttype/{fconttype}/categoryname/{fcategory}/contentdesc/{contdesc}'. Uploads a file
   * to the server.
   * 
   * @param is
   *          the input stream transmitted as JSON message
   * @param fname
   *          the filename given in {fname}
   * @param fcategory
   *          the file category given in {fcategory}
   * @param fconttype
   *          the file content type given in {fconttype}
   * @param contdesc
   *          the file description given in {contdesc}
   * @return a {@link ResponseObject}, containing 'success' if the upload was successful, 'failure' otherwise.
   * @throws IOException
   */
  @POST
  @Path("content/filename/{fname}/contenttype/{fconttype}/categoryname/{fcategory}/contentdesc/{contdesc}")
  @Consumes(MediaType.APPLICATION_OCTET_STREAM)
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject uploadContent(InputStream is, @PathParam(value = "fname") String fname,
      @PathParam(value = "fcategory") String fcategory, @PathParam(value = "fconttype") String fconttype,
      @PathParam(value = "contdesc") String contdesc) throws IOException {

    ResponseObject o = new ResponseObject();
    o.setResponseStatus(ResponseObject.failure);
    o.setResponseDesc("File not saved.");

    if (httpReq.getUserPrincipal() != null) {
      FileDTO fdto = new FileDTO(null);
      fdto.setDisplayedFilename(URLDecoder.decode(fname, "UTF-8"));
      Set<String> catSet = new HashSet<String>();
      catSet.add(URLDecoder.decode(fcategory, "UTF-8"));
      // check category and contentType ???
      fdto.setCategories(catSet);
      fdto.setOwner(httpReq.getUserPrincipal().getName());
      fdto.setContentType(fconttype);
      fdto.setDescription(URLDecoder.decode(contdesc, "UTF-8"));
      System.out.println(contdesc + " : " + URLDecoder.decode(contdesc, "UTF-8"));
      if (reqHandler.uploadFile(fdto, is) != null) {

        o.setResponseStatus(ResponseObject.success);
        o.setResponseDesc("File saved");
      }
    }
    return o;
  }

  /**
   * Handles a POST request on path 'users/register/{uname}'. Registers a new user to the application. The default role
   * for a newly created user is USER.
   * 
   * @param username
   *          the user name given in {uname}
   * @param pdto
   *          the password dto transmitted as JSON message
   * @return a {@link ResponseObject}, containing 'success' if the registration was successful, 'failure' otherwise
   */
  @POST
  @Path("users/register/{uname}")
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject registerUser(@PathParam(value = "uname") String username, PasswordDTO pdto) {

    System.out.println("registerUser erreicht");
    System.out.println(username);
    ResponseObject resp = new ResponseObject();

    int retval = reqHandler.register(new UserDTO(username), pdto);

    if (retval == 0) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("User " + username + " was created successfully. You can now login.");
    } else if (retval == 1) {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("We are sorry, the user name " + username + " already exists. Please try again.");
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("User " + username + " could not be created. That's all we know.");
    }

    return resp;

  }

  /**
   * Handles a POST request on path 'groups'. Creates a new group.
   * 
   * @param newGroup
   *          the group dto transmitted as JSON message
   * @return a {@link ResponseObject}, containing 'success' if creation was successful, 'failure' otherwise.
   */
  @POST
  @Path("groups")
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject createGroup(GroupDTO newGroup) {

    ResponseObject resp = new ResponseObject();

    if (newGroup.getGrpAdmin() == null) {
      newGroup.setGrpAdmin(httpReq.getUserPrincipal().getName());
    }

    if (reqHandler.generateGroup(httpReq.getUserPrincipal().getName(), newGroup)) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("Group " + newGroup.getName() + " was created successfully. Your are group admin.");
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("Group " + newGroup.getName() + " could not be created. That's all we know.");
    }

    return resp;

  }

  /**
   * Handles a POST request on path 'categories'. Creates a new category. This function should only be available to
   * administrators.
   * 
   * @param cdto
   *          the category dto
   * @return a {@link ResponseObject}, containing 'success' if the category was successfully created, 'failure'
   *         otherwise.
   */
  @POST
  @Path("categories")
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject createCategory(CategoryDTO cdto) {

    ResponseObject resp = new ResponseObject();

    if (reqHandler.generateCategory(httpReq.getUserPrincipal().getName(), cdto)) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("Category " + cdto.getCategoryName() + " with ContentType " + cdto.getContentType()
          + " was created successfully.");
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("Group " + cdto.getCategoryName() + " with ContentType " + cdto.getContentType()
          + " could not be created. That's all we know.");
    }

    return resp;

  }

  /*
   * ################ Updating Rescources ##############
   */
  /**
   * Handles a PUT request on path 'groups/{groupName}/newparticipant'. Adds the current principal user as pending to a
   * group.
   * 
   * @param gName
   *          the name of the group
   * @return a {@link ResponseObject} containing 'success' if user could be added, 'failure' otherwise
   */
  @PUT
  @Path("groups/{groupName}/newparticipant")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject addUserToGroup(@PathParam(value = "groupName") String gName) {

    boolean newParticipant = false;
    ResponseObject resp = new ResponseObject();
    newParticipant = reqHandler.addUserAsPendingToGroup(httpReq.getUserPrincipal().getName(), gName);

    if (newParticipant) {
      resp.setResponseDesc("Your were added to the list of pending users.");
      resp.setResponseStatus(ResponseObject.success);
    } else {
      resp.setResponseDesc("We could not add you to the list of pending users.");
      resp.setResponseStatus(ResponseObject.failure);
    }

    return resp;
  }

  /**
   * Handles a PUT request on path 'groups/{groupName}/accept/{username}'. Accepts a user to a group the current
   * principal is administrator of.
   * 
   * @param gName
   *          the name of the group given in {groupName}
   * @param uName
   *          the name of the user to add given in {username}
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @PUT
  @Path("groups/{groupName}/accept/{username}")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject acceptUserInGroup(@PathParam(value = "groupName") String gName,
      @PathParam(value = "username") String uName) {

    ResponseObject resp = new ResponseObject();

    if (reqHandler.acceptUserToGroup(httpReq.getUserPrincipal().getName(), gName, uName)) {
      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("User " + uName + " was added to group " + gName + ".");
    } else {
      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("An error occured while the user " + uName + " was added to group " + gName + ".");
    }

    return resp;
  }

  /**
   * Handles a PUT request on path 'preferences'. Adds a preference to the current principal user.
   * 
   * @param prefToAdd
   *          the preference dto to add transmitted as JSON message
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @PUT
  @Path("preferences")
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject addPreferenceToUser(PreferenceDTO prefToAdd) {

    ResponseObject resp = new ResponseObject();

    if (reqHandler.addPreferenceToUser(httpReq.getUserPrincipal().getName(), prefToAdd)) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("The preference " + prefToAdd.getName() + " was added list of preferences.");
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("We experienced an error adding the preference " + prefToAdd.getName()
          + " to your list of preferences.");
    }

    return resp;

  }

  /**
   * Handles a PUT request on path 'users/password'. Updates the password of the current principal user.
   * 
   * @param pwDto
   *          the password dto, transmitted as JSON message
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @PUT
  @Path("users/password")
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject updatePassword(PasswordDTO pwDto) {

    ResponseObject resp = new ResponseObject();

    boolean cond = reqHandler.updatePassword(httpReq.getUserPrincipal().getName(), new UserDTO(httpReq
        .getUserPrincipal().getName()), pwDto);

    if (cond) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("Password was updated successfully.");
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("We experienced an error while updating your password. That's all we know.");
    }

    return resp;
  }

  /*
   * ################ Deleting Rescources ##############
   */
  /**
   * Handles a DELETE request on path 'preferences/name/{prefname}/conttype/{conttype}'. Removes a preference from the
   * current principal user.
   * 
   * @param prefName
   *          the preference name, given by {prefname}
   * @param contentType
   *          the content type, given by {conttype}
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @DELETE
  @Path("preferences/name/{prefname}/conttype/{conttype}")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject removePreferencesFromUser(@PathParam(value = "prefname") String prefName,
      @PathParam(value = "conttype") String contentType) {

    ResponseObject respObj = new ResponseObject();

    if (reqHandler.deletePreference(httpReq.getUserPrincipal().getName(), new PreferenceDTO(contentType, prefName))) {

      respObj.setResponseStatus(ResponseObject.success);
      respObj.setResponseDesc("Preference " + prefName + " was removed from your account.");
    } else {

      respObj.setResponseStatus(ResponseObject.failure);
      respObj.setResponseDesc("Preference " + prefName
          + "could not be removed. Or another error occured. Sorry, that's all we know.");
    }

    return respObj;
  }

  /**
   * Handles a DELETE request on path 'groups/{groupName}/removeparticipant'. Removes the current principal user from a
   * group.
   * 
   * @param gName
   *          the name of the group the current principal should be removed from
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @DELETE
  @Path("groups/{groupName}/removeparticipant")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject removeUserFromGroup(@PathParam(value = "groupName") String gName) {

    boolean removedParticipant = false;
    ResponseObject resp = new ResponseObject();
    removedParticipant = reqHandler.removeUserFromGroup(httpReq.getUserPrincipal().getName(), httpReq
        .getUserPrincipal().getName(), gName);

    if (removedParticipant) {
      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("You left the group " + gName + ".");
    } else {
      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("We are sorry, but an error occured, while you left the group " + gName + ".");
    }

    return resp;

  }

  /**
   * Handles a DELETE request on path 'groups/{groupname}/removeparticipant/{username}'. Removes a user from a group.
   * Should be only available to group administrators.
   * 
   * @param gName
   *          the group name given in {groupname}
   * @param uName
   *          the user name given in {username}
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @DELETE
  @Path("groups/{groupname}/removeparticipant/{username}")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject removeUserFromGroupAsAdmin(@PathParam(value = "groupname") String gName,
      @PathParam(value = "username") String uName) {

    boolean removedParticipant = false;
    ResponseObject resp = new ResponseObject();

    removedParticipant = reqHandler.removeUserFromGroup(httpReq.getUserPrincipal().getName(), uName, gName);

    if (removedParticipant) {
      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("User " + uName + " was removed from group " + gName + ".");
    } else {
      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("User " + uName + " could not be removed from group" + gName + ". An error occured");
    }

    return resp;

  }

  /**
   * Handles a DELETE request on path 'users'. Deletes the current principal user from the application.
   * 
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   * @throws ServletException
   */
  @DELETE
  @Path("users")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject deleteUser() throws ServletException {

    ResponseObject resp = new ResponseObject();

    if (reqHandler.deleteUser(httpReq.getUserPrincipal().getName(), httpReq.getUserPrincipal().getName())) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("Your user account was deleted. If you regret your choice please register again.");

      httpReq.logout();
      httpReq.getSession().invalidate();
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("We experienced problems while deleting your account. We are sorry, "
          + "please write a mail to florian.sieck@tuhh.de.");
    }

    return resp;

  }

  /**
   * Handles a DELETE request on path 'groups/{groupname}/removepending/{username}'. Deletes a pending user from a
   * group. This method should only be available to the group administrator.
   * 
   * @param groupname
   *          the group name given in {groupname}
   * @param username
   *          the user name given in {username}
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @DELETE
  @Path("groups/{groupname}/removepending/{username}")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject deletePendingUserFromGroup(@PathParam(value = "groupname") String groupname,
      @PathParam(value = "username") String username) {

    ResponseObject resp = new ResponseObject();

    if (reqHandler.removeUserFromGroup(httpReq.getUserPrincipal().getName(), username, groupname)) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("User " + username + " was removed form the list of pending users of group " + groupname
          + ".");
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("There were problems while removing User " + username
          + " form the list of pending users of group " + groupname + ".");
    }

    return resp;

  }

  /**
   * Handles a DELETE request on path 'groups/{groupToDelete}'. Deletes a group the current principal user is
   * administrator of.
   * 
   * @param groupToDelete
   *          the name of the group to delete given in {groupToDelete}
   * @return a {@link ResponseObject}, containing 'success' if accepting the user to the group was successful, 'failure'
   *         otherwise.
   */
  @DELETE
  @Path("groups/{groupToDelete}")
  @Produces(MediaType.APPLICATION_JSON)
  public ResponseObject deleteGroup(@PathParam(value = "groupToDelete") String groupToDelete) {

    ResponseObject resp = new ResponseObject();

    if (reqHandler.deleteGroup(httpReq.getUserPrincipal().getName(), groupToDelete)) {

      resp.setResponseStatus(ResponseObject.success);
      resp.setResponseDesc("Group " + groupToDelete + " was deleted");
    } else {

      resp.setResponseStatus(ResponseObject.failure);
      resp.setResponseDesc("There were problems deleting the group " + groupToDelete + ". It could not be deleted.");
    }

    return resp;

  }

  /*
   * ################ Private Methods ##############
   */

  private FilterType getFilterType(String filtered, String filterPrefs) {

    FilterType filter = FilterType.NONE;
    if (httpReq.getUserPrincipal() != null) {
      if (filtered.equals("true")) {

        if (filterPrefs.equals("true")) {
          filter = FilterType.BOTH;
        } else {
          filter = FilterType.TRUSTFUL_USERS;
        }

      } else if (filterPrefs.equals("true")) {
        filter = FilterType.PREFERENCES;
      }
    }
    return filter;
  }
}
